package jeopardy.server;

import java.io.BufferedReader;
import java.io.Console;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.security.KeyStore;
import java.security.SecureRandom;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;

import jeopardy.common.Consts;
import jeopardy.server.accounts.UserAccountsManager;
import jeopardy.server.db.H2ServerDb;
import jeopardy.server.game.GameManager;
import jeopardy.server.stats.StatsManager;

import org.apache.log4j.Logger;

public class Server {

	private static Logger log = Logger.getLogger(Server.class);
	
	public static void main(String[] args) throws Exception{
		try{
			log.info("Jeopardy server starting...");
			
			SSLServerSocketFactory sslSsFactory = createSslSsFactory();
			if(sslSsFactory == null){
				log.info("Error crearing SSL Server Socket Factory...");
				return;
			}
			
			H2ServerDb dbStore = createDbStore();
			if(dbStore == null){
				log.error("Error creating Database instance...");
				return;
			}
			
			
			Thread userAccountsThread = new Thread(
					new UserAccountsManager(
							sslSsFactory.createServerSocket(Consts.SERVER_PORT_USER_ACCOUNT),
							dbStore
					)
			);
			userAccountsThread.start();
			
			Thread gameManagerThread = new Thread(
					new GameManager(sslSsFactory.createServerSocket(Consts.SERVER_PORT_GAME),
							dbStore
					)
			);
			gameManagerThread.start();
			
			Thread statsThread = new Thread(
					new StatsManager(sslSsFactory.createServerSocket(Consts.SERVER_PORT_STATS),
							dbStore
					)
			);
			statsThread.start();
			
		}catch(Exception e){
			log.error("Error initializing server...  enable debug logging for more information");
			log.debug("Error initializing server", e);
		}
	}
	
	private static H2ServerDb createDbStore(){
		try{
			Reader reader = new InputStreamReader(System.in);
			BufferedReader in = new BufferedReader(reader);
			
			System.out.println("Please enter the database URL:");
			System.out.print("> ");
			String dburl = in.readLine();
			
			System.out.println("Please enter the database user name:");
			System.out.print("> ");
			String dbuser = in.readLine();
			
			System.out.println("Please enter the password:");
			System.out.print("> ");
			
			char[] password = System.console().readPassword();
			//char[] password = in.readLine().toCharArray(); 
			
			H2ServerDb dbstore = new H2ServerDb(dburl, dbuser, password);
			
			return dbstore;
		}catch(Exception e){
			log.error("Error creating SSL Socket Factory, enable debug logging for more information");
			log.debug("SSL Socket Factory creation error", e);
			return null;
		}
	}

	private static SSLServerSocketFactory createSslSsFactory(){
		try{
			Reader reader = new InputStreamReader(System.in);
			BufferedReader in = new BufferedReader(reader);
			
			System.out.println("Please enter the full path to the keystore for SSL:");
			System.out.print("> ");
			String jksPath = in.readLine();
			
			System.out.println("Please enter the password for the keystore:");
			System.out.print("> ");
			
			char[] keyPassword = System.console().readPassword();
			//char[] keyPassword = in.readLine().toCharArray(); 
			
			FileInputStream keyFile = new FileInputStream(jksPath); 
	
			KeyStore keyStore = KeyStore.getInstance(ServerConsts.SSL_LOCAL_KEYSTORE_TYPE);
			keyStore.load(keyFile, keyPassword);
			 
			KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(ServerConsts.SSL_KEYMANAGER_ALGORITHM);
			keyManagerFactory.init(keyStore, keyPassword);
			 
			KeyManager keyManagers[] = keyManagerFactory.getKeyManagers();
			
			SSLContext sslContext = SSLContext.getInstance(ServerConsts.SSL_VERSION);
			sslContext.init(keyManagers, null, new SecureRandom());
			
			String[] supportedCiphers = {
					"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
					"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
					"TLS_RSA_WITH_AES_128_CBC_SHA256",
					"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
					"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"
			};
			sslContext.getSupportedSSLParameters().setCipherSuites(supportedCiphers);
			
			SSLServerSocketFactory socketFactory = sslContext.getServerSocketFactory();
	
			keyFile.close();
			
			return socketFactory;
		}catch(Exception e){
			log.error("Error creating SSL Socket Factory, enable debug logging for more information");
			log.debug("SSL Socket Factory creation error", e);
			return null;
		}
	}
}
